设计一个消息中间件的前置(三)| 数据结构及高可用设计

前两篇讲到了基本思路和netty+protobuf框架,今天这篇介绍一下前置的基本数据结构及用户校验,熔断的流程。

数据源及高可用

前置的数据源有两个,按照优先级来说,应该是这样的顺序:

  1. 缓存(Redis)
  2. 数据库(MySQL)——>前置内存

其中前置对缓存的访问使用实时读的方式,对数据库的访问使用定时读取全量数据,更新本地内存的方式。其主要思路是减少对数据库的并发访问,此外,考虑到缓存和数据库都可能出现宕机的情况,为了保证前置仍然可用,我们需要保证前置的内存中有一份最新的全量数据。

具体来说,每一次接收客户端校验请求时,我们优先从Redis获取数据,如果Redis客户端获取异常,则从内存中获取信息校验并返回给客户端。前置启动时需要开启一个定时线程,每隔一定时间同步Mysql数据和内存。

这个设计主要是为了保证服务的高可用,考虑数据源异常总共有四种场景:

  1. redis异常:可以更新权限信息,前置从mysql中定时同步数据;
  2. mysql异常:可以更新权限信息,前置优先从redis获取数据;
  3. mysql和redis都异常:无法更新权限信息,前置从本地内存中获取数据进行校验;
  4. 所有前置节点异常:启动应急方案,客户端直连mq集群,由mq上的权限校验功能来校验用户权限。

数据结构

在上一篇中介绍了protobuf的基础结构,发送端发送一个用户名+密码的组合,redis返回校验数据和路由地址。这个算是准入认证+路由机制,而进一步可以实现区分topic的权限校验。protobuf数据结构设计如下:

syntax = "proto3";
message request {
    string usrname = 1;
    string pwd = 2;
    string updateTime = 3;
}
message response {
    string retcode = 1;
    string updateTime = 2;
    string address = 3;
    map<string,string> permission = 4;
}

retCode有几种类型的值:

int NO_NEED_UPDATE = 1;                //无需校验
int WRONG_PASSWORD = 2;                //密码错误
int AUTHORIZATION_PASS = 3;            //校验通过
int SERVER_ERROR = 4;                  //服务异常

我在request中增加了一个updateTime,在response中增加了一个updateTime和类型为map的permission键值对结构。

updateTime是一个用于判断是否需要更新本地数据的开关,服务端收到request中的updateTime时,比对数据源中该用户的权限更新时间是否大于这个updateTime,如果不需要更新,则返回NO_NEED_UPDATE,否则就去数据源获取一下数据并带上数据源中的更新时间,生成response返回给客户端。这一设计的基本用途是减少无用的网络的传输和数据源访问操作。

permission这个map主要是用来存放从数据源中拿到的该用户的权限信息,返回给客户端后,在客户端本地保存一份。而后在生产者每次调用producer.send或者消费者每次调用consumer.poll方法时,在内存中校验一次是否有这个队列的权限。

基于request和response的结构,在尽量减少数据源读操作的情况下,Redis缓存和内存中的数据结构就很明确了:

键值对:
用户名 = 密码 
用户名:address = 路由地址
用户名:updateTime = 用户权限最后一次更新时间
MAP:
用户名:permission = {TOPICNAME = r/w/rw}

附上校验过程的伪代码:

if (checkPassword(request.getUserName) {
    if (checkUpdateTime(request.getUpdateTime) {
      return NO_NEED_UPDATE;
    } else {
      try {
          putAddressToResponse();
          putPermissionToResponse();
          putUpdateTimeToResponse();
          return AUTHORIZATION_PASS;
       } catch (Exception e) {
           return SERVER_ERROR;    //获取数据异常则返回服务异常
       }
    }
} else {
    return WRONG_PASSWORD;
}

熔断及服务降级设计

熔断和服务降级的机制不管触发条件是什么,我们首先要保证能提供熔断的能力。这里考虑使用准实时熔断机制。
客户端定时访问服务端,重复权限校验的流程,如果触发了熔断条件,数据源中的校验数据会被更新并反馈给客户端,客户端接收到WRONG_PASSWORD(拒绝该用户)时断开连接,并等待一定时间后重试。

消息中间件是一个可以很方便为系统实现服务降级功能的组件,只要将功能按照TOPIC来区分,经过TOPIC的权限校验,可以控制哪个TOPIC允许发送消息,哪个TOPIC允许接收消息。客户端在每次发送和接收时根据从前置上获取到的权限,进行一次复杂度为O(1)的判断,通过后才能进行发送和接收操作。如果是对某个topic的权限进行了更新,则会在对某个TOPIC的每次发送和接收操作时被拒绝,等待一段时间后重试。

当然,存放本地内存的方式其实只适合那些比较“遵守规则”的用户,也就是企业级内部用户,如果需要对外提供服务,权限校验功能可不能仅仅保存在客户端内存中,还应该在MQ上也加上配套的权限校验功能。

更进一步的方案

考虑这套方案,在熔断的设计上并不是即时生效的,时效性的提高可以考虑两种方案:

  1. 减少客户端两次校验的间隔时间,需要调优netty服务的效率
  2. 客户端改为长连接,需要配套心跳机制等。这时前置的整体架构就类似RocketMQ的NameServer了。

其实第一个方案中间隔时间减少到一定程度后,就可以考虑使用第二个方案了,毕竟每次创建连接的消耗是很大的。具体还是根据实际情况来考虑吧。

此外,上面写的这套方案中,每次服务端接收数据后都会在线程中阻塞式地访问数据源而后返回反馈,对更加大量并发的情况下,可以考虑使用异步处理的方式。

网络上有很多netty服务端优化的文章,这里就不一一列举了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容